//
// Created by dawn on 2025/4/11.
//

#include "ShopMenu.h"


ShopMenu::ShopMenu(ItemService &item_service, const MainMenu::AppState &app_state):
account(app_state.account),item_service(item_service),view_state(app_state.isLoggedIn ? 1 : 0),cart(app_state.account) {
    shop_items = item_service.queryAllItems();
    page_view.item_number = static_cast<int>(shop_items.size());
    page_view.total_pages =  std::ceil(static_cast<double>(page_view.item_number)/page_view.number_per_page);
    setTitle(titleToken());
    if (app_state.isLoggedIn) {
        this->cart = item_service.initCart(app_state.account);
    }
}

std::string ShopMenu::titleToken(const std::string &token ) const {
    switch (view_state) {
        case 0: return "Browsing";
        case 1: return "Shopping: all items";
        case 2: return "Searching by name: " + token;
        case 3: return "Searching by category: " + token;
        case 4: return "Searching by price: " + token;
        default: return "Shopping";
    }
}

void ShopMenu::display() const {
    clearScreen();
    std::cout << "======= " << title
    << " [" << this->page_view.current_page_number+1
    << "/" << page_view.total_pages << "]"
    << " =======\n";
    showPage();
    for (size_t i = 0; i < items.size(); ++i) {
        std::cout << "[" << i + 1 << "] " << items[i].description << std::endl;
    }
    std::cout << "[0] Exit" << std::endl;
    std::cout << "OPTION: ";
}

void ShopMenu::run() const {
    std::string input;
    while (true) {
        display();
        std::getline(std::cin, input);
        if (input.length() > 1 || input.empty()) {
            FormMenu::noticeTheEnter("Invalid choice, enter to try again");
            continue;
        }
        const int choice = input.at(0) - '0';
        if (choice == 0) {
            break;
        }
        if (choice > 0 && static_cast<size_t>(choice) <= items.size()) {
            clearScreen();
            items[choice-1].action();
        }
        else {
            FormMenu::noticeTheEnter("Invalid choice, enter to try again");
        }
    }
}

/// 页面展示
void ShopMenu::showPage() const {
    // 商品为空时提示
    if (shop_items.empty()) {
        std::cout << "No item" << std::endl;
        return;
    }

    // 获取当前页需要展示的物品的索引
    const int from = page_view.current_page_number * page_view.number_per_page;
    const int to = (from + page_view.number_per_page > page_view.item_number) ? page_view.item_number : from + page_view.number_per_page;

    for (int i = from; i < to; ++i) {
        std::cout << "Item index: [" << i+1 << "]" << std::endl;
        shop_items[i].display();
    }
}

/// 下一页
void ShopMenu::nextPage() {
    // 如果已经是最后一页, 跳转回到第一页
    if (page_view.current_page_number == page_view.total_pages - 1) {
        page_view.current_page_number = 0;
    }
    else
        this->page_view.current_page_number++;
}

/// 上一页
void ShopMenu::prevPage() {
    // 如果已经是第一页, 跳转到最后一页
    if (page_view.current_page_number == 0) {
        page_view.current_page_number = page_view.total_pages-1;
    }
    else
        this->page_view.current_page_number--;
}

/// 查询所有物品
/// @param isLoggedIn 登陆的状态
void ShopMenu::showAllItems(const bool isLoggedIn) {
    // 将所有的物品加载到vector中
    this->shop_items = this->item_service.queryAllItems();
    // 更新物品数与页数
    page_view.item_number = static_cast<int>(shop_items.size());
    page_view.current_page_number = 0;
    page_view.total_pages =  std::ceil(static_cast<double>(page_view.item_number)/page_view.number_per_page);
    // 根据登陆状态来更改输出
    this->view_state = isLoggedIn?1:0;
    setTitle(titleToken());
}

/// 根据名字搜索物品
void ShopMenu::searchByName(){
    // 获取输入
    const std::string item_name = Item::input_name("Search item by name: ");
    // 查询物品并将结果加载道vector中
    this->shop_items = this->item_service.queryItemsByName(item_name);
    // 更新页数信息
    page_view.item_number = static_cast<int>(shop_items.size());
    page_view.current_page_number = 0;
    page_view.total_pages =  std::ceil(static_cast<double>(page_view.item_number)/page_view.number_per_page);
    // 更新显示
    this->view_state = 2;
    setTitle(titleToken(item_name));
}

/// 根据类别搜索物品
void ShopMenu::searchByCategory() {
    // 获取输入
    const auto category = Item::input_category("Search item by category: ");
    // 查询物品并将结果加载道vector中
    this->shop_items = this->item_service.queryItemsByCategory(category);
    // 更新页数信息
    page_view.item_number = static_cast<int>(shop_items.size());
    page_view.current_page_number = 0;
    page_view.total_pages =  std::ceil(static_cast<double>(page_view.item_number)/page_view.number_per_page);
    // 更新显示
    this->view_state = 3;
    setTitle(titleToken(category));
}

/// 根据价格搜索物品
void ShopMenu::searchByPrice() {
    // 获取输入
    const double min_price = Item::input_price("min price: ");
    const double max_price = Item::input_price("max price: ");
    // 查询物品并将结果加载道vector中
    this->shop_items = this->item_service.queryItemsByPrice(min_price, max_price);
    // 更新页数
    page_view.item_number = static_cast<int>(shop_items.size());
    page_view.current_page_number = 0;
    page_view.total_pages =  std::ceil(static_cast<double>(page_view.item_number)/page_view.number_per_page);
    // 更新显示
    std::ostringstream item_price;
    item_price << min_price;
    item_price << "-";
    item_price << max_price;
    this->view_state = 4;
    setTitle(titleToken(item_price.str()));
}

void ShopMenu::cartItem() {
    int item_index = -1;
    const int from = page_view.current_page_number * page_view.number_per_page;
    const int to = (from + page_view.number_per_page > page_view.item_number) ? page_view.item_number : from + page_view.number_per_page;
    FormMenu item_select_menu("Which item do you want to put into cart");
    item_select_menu.addItem(shop_items[from].get_name(),
        [&item_index,from]() {
            item_index = from;
        });
    if (to-1!=from) {
        item_select_menu.addItem(shop_items[to-1].get_name(),
           [&item_index, to]() {
               item_index = to-1;
           });
    }
    item_select_menu.addItem("Cancel",
        []() {});
    clearScreen();
    this->showPage();
    item_select_menu.run();

    if (item_index==-1) {
        return;
    }

    if (const int item_id = shop_items[item_index].get_id();this->cart.checkItem(item_id)) {
        FormMenu ackMenu("This item is already in cart");
        ackMenu.addItem("Add quantity",
            [this,item_index]() {
                const int addition = Cart::inputItemNumber("Enter quantity: ");
                const int quantity = this->cart.getCartItemQuantity(item_index);
                this->cart.updateCartItem(item_index,quantity + addition);
            });
        ackMenu.addItem("Cancel",[]() {});
        ackMenu.run();
    }
    else if (const int quantity = Cart::inputItemNumber("Quantity: "); quantity > 0) {
        this->cart.addCartItem(shop_items[item_index],quantity);
    }
    else {
        std::cout << "Quantity is zero, nothing change in cart";
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
}

void ShopMenu::updateCartItem() {
    if (this->cart.isCartEmpty()) {
        FormMenu::noticeTheEnter("My cart is Empty");
        return;
    }
    const int index = this->cart.inputItemIndex();
    if (const int quantity =
        Cart::inputItemNumber("Updated quantity[ "
            + std::to_string(this->cart.getCartItemQuantity(index)) + " -> ? ]: "); quantity == 0) {
        FormMenu ackMenu("You have input 0 in quantity");
        ackMenu.addItem("Delete this item from cart",
            [this,index]() {
                this->cart.removeCartItem(index);
            });
        ackMenu.addItem("Cancel",
            [this]() {
                std::cout << "Nothing changed" << std::endl;
            });
        ackMenu.run();
    }
    else {
        this->cart.updateCartItem(index, quantity);
        std::cout << "Item quantity updated" << std::endl;
    }
}

void ShopMenu::deleteCartItem() {
    if (this->cart.isCartEmpty()) {
        FormMenu::noticeTheEnter("My cart is Empty");
        return;
    }
    FormMenu delete_menu("Which way do you want to delete items");
    delete_menu.addItem("Delete one item from cart",
        [this]() {
            const int index = this->cart.inputItemIndex();
            this->cart.removeCartItem(index);
            std::cout << "Item removed from cart" << std::endl;
        });
    delete_menu.addItem("Multi-Select Delete",
        [this]() {
            const std::string input = FormMenu::getStrInput("input indexes separated by space:");
            std::istringstream iss(input);
            int num;
            std::set<int> id_set;
            while (iss>>num) {
                if (this->cart.isInList(num-1))
                id_set.insert(this->cart.get_cart_list().itemId_vector[num-1]);
            }

            for (const int &id : id_set) {
                this->cart.removeCartItemById(id);
            }

            std::cout << id_set.size() <<" items removed from cart" << std::endl;
        });
    delete_menu.addItem("Delete all items from cart",
        [this]() {
            this->cart.removeAllCartItem();
            std::cout <<  "All items removed" << std::endl;
        });
    delete_menu.addItem("Cancel",[](){});
    this->cart.showCart();
    delete_menu.run();
}

void ShopMenu::showCartMenu() {
    Menu cart_menu("My cart");
    cart_menu.addItem("Update my cart",
        [this]() {
            this->updateCartItem();
        });
    cart_menu.addItem("Delete cart",
        [this]() {
            this->deleteCartItem();
    });
    cart_menu.addItem("Buy items in Cart",
        [this]() {
            this->buyCart();
        });
    cart_menu.run([this]() {
        this->cart.showCart();
    });
}

void ShopMenu::updateCart() const {
    if (!this->cart.is_cart_modified()) {
        return;
    }
    if (!item_service.updateCart(this->cart)) {
        throw std::runtime_error("Failed to update cart");
    }
}

void ShopMenu::buyMenu() const {
    FormMenu buy_menu("Which way do you want to buy");
    buy_menu.addItem("Buy single item",
        [this]() {
            this->buySingleItem();
        });
    buy_menu.addItem("Buy multiple items",
        [this]() {
            this->buyMultiItem();
        });
    buy_menu.addItem("Cancel",
        [](){});
    buy_menu.run();
}

void ShopMenu::buySingleItem() const {
    // select item
    int item_index = -1;
    const int from = page_view.current_page_number * page_view.number_per_page;
    const int to = (from + page_view.number_per_page > page_view.item_number) ? page_view.item_number : from + page_view.number_per_page;
    FormMenu item_select_menu("Which item do you want to put into cart");
    item_select_menu.addItem(shop_items[from].get_name(),
        [&item_index,from]() {
            item_index = from;
        });
    if (to-1!=from) {
        item_select_menu.addItem(shop_items[to-1].get_name(),
           [&item_index, to]() {
               item_index = to-1;
           });
    }
    item_select_menu.addItem("Cancel",
        []() {});
    clearScreen();
    this->showPage();
    item_select_menu.run();

    // generate order
    if (item_index!=-1) {
        const int stock = item_service.getItemStock(shop_items[item_index].get_id());
        const int quantity = Cart::inputItemNumber("Enter quantity",stock);
        std::vector<Cart::SomeItems> items;
        Cart::SomeItems new_item = {
            shop_items[item_index].get_id(),
            shop_items[item_index].get_name(),
            shop_items[item_index].get_price(),
            quantity,
            shop_items[item_index].get_discount()
        };
        new_item.set_discount_price();
        items.emplace_back(new_item);

        if (!item_service.checkItemStock(items)) {
            FormMenu::noticeTheEnter("Over stock");
        }
        else {
            const std::string address = FormMenu::getStrInput("Enter address: ");

            if (item_service.generateOrder(this->account,items,address)) {
                FormMenu::noticeTheEnter("Order generated");
            }
            else {
                FormMenu::noticeTheEnter("Fail to generate order");
            }
        }
    }
}

void ShopMenu::buyMultiItem() const {
    std::vector<Cart::SomeItems> items;

    const std::string input = FormMenu::getStrInput("input indexes separated by space:");
    std::istringstream iss(input);
    int num;
    std::set<int> id_set;
    while (iss>>num) {
        if (num > 0 && num <= shop_items.size()) {
            id_set.insert(num-1);
        }
    }

    for (const auto &id : id_set) {

        Cart::SomeItems item;
        item.itemId = shop_items[id].get_id();
        item.itemName = shop_items[id].get_name();
        item.itemPrice = shop_items[id].get_price();
        item.discount = shop_items[id].get_discount();
        item.set_discount_price();

        std::cout<< item.itemName << " Price: " << item.itemPrice << std::endl;
        const int stock = item_service.getItemStock(item.itemId);
        item.quantity = Cart::inputItemNumber("Enter quantity",stock);

        items.push_back(item);
    }

    if (!item_service.checkItemStock(items)) {
        FormMenu::noticeTheEnter("Over stock");
    }
    else {
        const std::string address = FormMenu::getStrInput("Enter address: ");

        if (item_service.generateOrder(this->account,items,address)) {
            FormMenu::noticeTheEnter("Order generated");
        }
        else {
            FormMenu::noticeTheEnter("Fail to generate order");
        }
    }
}

void ShopMenu::buyCart(){
    std::vector<Cart::SomeItems> items;
    FormMenu select_menu("which way do you want to buy");
    select_menu.addItem("Buy multiple items",
            [&items,this]() {
                const std::string input = FormMenu::getStrInput("input indexes separated by space:");
                std::istringstream iss(input);
                int num;
                std::set<int> id_set;
                while (iss>>num) {
                if (this->cart.isInList(num-1))
                    id_set.insert(this->cart.get_cart_list().itemId_vector[num-1]);
                }

                for (const int &id : id_set) {
                    items.emplace_back(this->cart.get_cart_list().items_map.at(id));
                }
            });
    select_menu.addItem("Buy all items in cart",
        [&items, this]() {
            items = this->cart.get_cart_items();
        });
    this->cart.showCart();
    select_menu.run();

    if (!item_service.checkItemStock(items)) {
        FormMenu::noticeTheEnter("Over stock");
        return;
    }

    const std::string address = FormMenu::getStrInput("Enter address: ");

    if (item_service.generateOrder(this->account,items,address)) {
        FormMenu::noticeTheEnter("Order generated");
        for (const auto &item : items) {
            this->cart.removeCartItemById(item.itemId);
        }
    }
    else {
        FormMenu::noticeTheEnter("Fail to generate order");
    }
}

